home *** CD-ROM | disk | FTP | other *** search
/ io Programmo 16 / IOPROG_16.ISO / soft / macaxsdk / macsdk.hqx / ActiveX DR3 SDK / ActiveX SDK / QuickStart / JSButton•.rsrc / dFRK_5001 < prev    next >
Encoding:
Text File  |  1997-09-18  |  13.2 KB  |  514 lines

  1. // =================================================================================
  2. //
  3. // >>> ⌐ 1996-1997 Microsoft Corporation.  All rights reserved. <<<
  4. //
  5. // =================================================================================
  6.  
  7. #include "AXControlHeaders.h"
  8. #include "VariantUtil.h"
  9. #include "CJSButtonControl.h"
  10.  
  11. #pragma mark === CJSButtonControl::Construction & Destruction ===
  12.  
  13. const Int16    OvalSize = 20;
  14.  
  15. //=--------------------------------------------------------------------------=
  16. //  CJSButtonControl::CJSButtonControl    
  17. //=--------------------------------------------------------------------------=
  18.  
  19. CJSButtonControl::CJSButtonControl(void)
  20. {
  21.     mScriptClick = false;
  22.     mValue = NewPtrClear(256);
  23.  
  24.     mLastMouseUpTime = ::TickCount() - ::GetDblTime();
  25.  
  26.     // Add support for an outgoing event interface
  27.     AddConnectionPoint(IID_IDispatch);
  28. }
  29.  
  30.  
  31. //=--------------------------------------------------------------------------=
  32. //  CJSButtonControl::~CJSButtonControl
  33. //=--------------------------------------------------------------------------=
  34.  
  35. CJSButtonControl::~CJSButtonControl()
  36. {
  37.     DisposePtr(mValue);
  38. }
  39.  
  40. #pragma mark === CJSButtonControl::IUnknown Interface ===
  41.  
  42. //=--------------------------------------------------------------------------=
  43. //    CJSButtonControl::IUnknown::QueryInterface
  44. //=--------------------------------------------------------------------------=
  45. //    Returns a pointer to the specified interface on a component to which a
  46. //    client currently holds an interface pointer.
  47. //
  48. STDMETHODIMP
  49. CJSButtonControl::QueryInterface(REFIID inRefID, void** outObj)
  50. {
  51.     AXErrorCode    Result = E_NOINTERFACE;
  52.     void*         pv = nil;
  53.  
  54.     // First try all the interfaces we implement directly
  55.     if ( inRefID == IID_IControl )    
  56.         pv = (void*)(IControl* ) this;
  57.     else if ( inRefID == IID_IDispatch )
  58.         pv = (void*)(IDispatch* ) this;
  59.     else    
  60.     { 
  61.         // CBaseControl
  62.         Result = CBaseControl::QueryInterface(inRefID, outObj);
  63.  
  64.         // CBaseDispatch
  65.         if ( Result == E_NOINTERFACE )
  66.             Result = CBaseDispatch::QueryInterface(inRefID, outObj);
  67.             
  68.         // CBaseCPServer
  69.         if ( Result == E_NOINTERFACE )
  70.             Result = CBaseCPServer::QueryInterface(inRefID, outObj);
  71.             
  72.         if ( Result != E_NOINTERFACE )
  73.             return Result;
  74.     }
  75.     
  76.     *outObj = pv;
  77.  
  78.     // if we got an interface, ref it and return ok
  79.     if ( pv )
  80.     {
  81.          ((IUnknown*) pv)->AddRef();
  82.         Result = S_OK;
  83.     }
  84.     
  85.     return Result;
  86. }
  87.  
  88.  
  89. #pragma mark === CJSButtonControl::IControl Interface ===
  90.  
  91.  
  92. //=--------------------------------------------------------------------------=
  93. //  CJSButtonControl::IControl::Draw
  94. //=--------------------------------------------------------------------------=
  95.  
  96. STDMETHODIMP
  97. CJSButtonControl::Draw(AXDrawContext* inContext)
  98. {
  99.     Str255    Name;
  100.     Int16     NameWidth, NameHeight, ButtonWidth, ButtonHeight;
  101.     Rect    ButtonRect = inContext->Location;
  102.     
  103.     // Position the Button rect
  104.     InsetRect(&ButtonRect, 5, 5);
  105.     
  106.     // Erase the area
  107.     EraseRoundRect(&ButtonRect, OvalSize, OvalSize);
  108.  
  109.     // Frame the button
  110.     PenSize(2, 2);
  111.     FrameRoundRect(&ButtonRect, OvalSize, OvalSize);
  112.     PenSize(1, 1);
  113.     
  114.     // Center the text
  115.     ::TextFont(applFont);
  116.     ::TextFace(0);
  117.     ::TextSize(12);
  118.     strcpy((Char8*) Name, mValue);
  119.     c2pstr((Char8*) Name);
  120.     NameWidth = ::StringWidth(Name);
  121.     NameHeight = 12;
  122.     ButtonWidth = ButtonRect.right - ButtonRect.left;
  123.     ButtonHeight = ButtonRect.bottom - ButtonRect.top;
  124.     ::MoveTo(ButtonRect.left+ ((ButtonWidth - NameWidth) / 2), 
  125.             ButtonRect.top + ((ButtonHeight - NameHeight) / 2 + NameHeight));
  126.     
  127.     // Draw the name
  128.     ::DrawString(Name);
  129.     
  130.     return S_OK;
  131. }
  132.  
  133.  
  134. //=--------------------------------------------------------------------------=
  135. //  CJSButtonControl::IControl::DoMouse    
  136. //=--------------------------------------------------------------------------=
  137.  
  138. STDMETHODIMP
  139. CJSButtonControl::DoMouse(AXMouseEventType inMouseET, AXPlatformEvent* inEvent)
  140. {
  141. #pragma unused (inEvent)
  142.     switch (inMouseET) 
  143.     {
  144.         case kAXMouseDown:
  145.         {
  146.             AXDrawContext Context = {kAXBeginPortType};
  147.             
  148.             if ( mContainerSiteP->AcquireContext(mActiveContext->GetContextID(), &Context) == S_OK )
  149.             {
  150.                 Rect    ButtonRect = Context.Location;
  151.                 
  152.                 // Position the Button rect
  153.                 ::InsetRect(&ButtonRect, 5, 5);
  154.                 
  155.                 // Do the button behavior
  156.                 ::InvertRoundRect(&ButtonRect, OvalSize, OvalSize);
  157.                 WaitClick();
  158.                 ::InvertRoundRect(&ButtonRect, OvalSize, OvalSize);
  159.                 
  160.                 // Release the context
  161.                 mContainerSiteP->ReleaseContext(&Context);
  162.                 
  163.                 // Broadcast the event
  164.                 Broadcast(IID_IDispatch, kEventOnClick, nil);
  165.             }
  166.             
  167.             break;
  168.         }
  169.             
  170.     }
  171.  
  172.     return S_OK;
  173. }
  174.  
  175. #pragma mark === CJSButton::IPersistPropertyBag Override Methods ===
  176.  
  177. //=--------------------------------------------------------------------------=
  178. //    CJSButtonControl::IPersistPropertyBag::InitNew
  179. //=--------------------------------------------------------------------------=
  180. //
  181. STDMETHODIMP
  182. CJSButtonControl::InitNew(void)
  183. {
  184.     // Call the base control to set up defaults for ID, width and height
  185.     CBaseControl::InitNew();    
  186.     
  187.     // We can use the property bag interface on the Object Desc 
  188.     // to retrieve default property values
  189.     if ( mObjectDesc )
  190.     {
  191.         IPropertyBag* PropertyBag = nil;
  192.         
  193.         mObjectDesc->QueryInterface(IID_IPropertyBag, &PropertyBag);
  194.         
  195.         // if we got a property bag interface, use it to get the property value
  196.         if ( PropertyBag )
  197.         {
  198.             GetValueFromPropertyBag(PropertyBag, nil);
  199.             PropertyBag->Release();
  200.         }
  201.     }
  202.     else    // Can't do much else than this
  203.         strcpy(mValue, "ClickMe");
  204.     
  205.     return S_OK;
  206. }
  207.  
  208.  
  209. //=--------------------------------------------------------------------------=
  210. //    CJSButtonControl::IPersistPropertyBag::Load
  211. //=--------------------------------------------------------------------------=
  212. //
  213. STDMETHODIMP
  214. CJSButtonControl::Load(IPropertyBag* PropertyBag, IErrorLog* ErrorLog)
  215. {
  216.     AXErrorCode Result = CBaseControl::Load(PropertyBag, ErrorLog);
  217.     
  218.     GetValueFromPropertyBag(PropertyBag, ErrorLog);
  219.  
  220.     return S_OK;
  221. }
  222.  
  223.  
  224. //=--------------------------------------------------------------------------=
  225. //    CJSButtonControl::IPersistPropertyBag::Save
  226. //=--------------------------------------------------------------------------=
  227. //
  228. STDMETHODIMP
  229. CJSButtonControl::Save(IPropertyBag* PropertyBag, BOOL ClearDirty, BOOL SaveAllProperties)
  230. {
  231.     #pragma unused(ClearDirty, SaveAllProperties)
  232.     
  233.     AXErrorCode Result = CBaseControl::Save(PropertyBag, ClearDirty, SaveAllProperties);
  234.     
  235.     if ( Result == S_OK )
  236.     {
  237.         VARIANT    Var;
  238.  
  239.         // Fill in the variant structure
  240.         VariantInit(&Var);
  241.         VarSetBStr(&Var, mValue);
  242.  
  243.         // Write our value property's value
  244.         Result = PropertyBag->Write("value", &Var);
  245.  
  246.         // Free the variant string
  247.         SysFreeString(Var.n1.n2.n3.bstrVal);
  248.     }
  249.     
  250.     return Result;
  251. }
  252.  
  253.  
  254. #pragma mark === CJSButtonControl::IDispatch methods ===
  255.  
  256. /*****************************************************************/
  257.  
  258. //=--------------------------------------------------------------------------=
  259. //  CJSButtonControl::IDispatch::GetIDsOfNames    
  260. //=--------------------------------------------------------------------------=
  261. STDMETHODIMP
  262. CJSButtonControl::GetIDsOfNames(REFIID inRefID, char** inNames, unsigned int inNameCount, 
  263.                                 LCID inLocaleID, DISPID* outDispID)
  264. {
  265. #pragma unused(inRefID)
  266. #pragma unused(inLocaleID)
  267.  
  268.     AXErrorCode Result = NOERROR;
  269.     
  270.     // Loop through all the names we know about and return the DISPID
  271.     for (int i = 0; i < inNameCount && Result == NOERROR; i++)
  272.     {
  273.         if ( strcmp( inNames[i], "name" ) == 0 )
  274.             outDispID[i] = kPropName;
  275.         else if ( strcmp( inNames[i], "value" ) == 0 )
  276.             outDispID[i] = kPropValue;
  277.         else if ( strcmp( inNames[i], "click" ) == 0 )
  278.             outDispID[i] = kMethodClick;
  279.         else
  280.             outDispID[i] = -1;
  281.             
  282.         if (outDispID[i] == -1)
  283.             Result = DISP_E_UNKNOWNNAME;
  284.     }
  285.     
  286.     return Result;
  287. }
  288.  
  289.  
  290. //=--------------------------------------------------------------------------=
  291. //  CJSButtonControl::IDispatch::Invoke    
  292. //=--------------------------------------------------------------------------=
  293. STDMETHODIMP
  294. CJSButtonControl::Invoke(DISPID inDispID, REFIID inRefID, LCID inLocaleID, unsigned short inFlags, DISPPARAMS* inParams,
  295.                           VARIANT* outResult, EXCEPINFO* outExcepInfo, unsigned int* outArgErr)
  296. {
  297. #pragma unused(inRefID)
  298. #pragma unused(inLocaleID)
  299. #pragma unused(outExcepInfo)
  300. #pragma unused(outArgErr)
  301.  
  302.     AXErrorCode Result = NOERROR;
  303.     
  304.     // Initialize the return result
  305.     VariantInit(outResult);
  306.  
  307.     // if this is a method call
  308.     if (inFlags & DISPATCH_METHOD)    
  309.     {
  310.         switch (inDispID)
  311.         {
  312.             case kMethodClick:
  313.                 mScriptClick = true;
  314.                 DoMouse(kAXMouseDown, nil);
  315.                 mScriptClick = false;
  316.                 break;
  317.         }
  318.     }
  319.     else if (inFlags & DISPATCH_PROPERTYGET)     // if this is a Get Property call
  320.     {
  321.         char* vResult = nil;
  322.  
  323.         switch (inDispID)
  324.         {
  325.             case kPropName:        // Return the ID of the control
  326.             {
  327.                 char    Name[256];
  328.                 
  329.                 GetID(256, Name);
  330.                 outResult->n1.n2.vt = VT_BSTR;
  331.                 outResult->n1.n2.n3.bstrVal = SysAllocStringLen(Name, strlen(Name));
  332.                 break;
  333.             }
  334.                     
  335.             case kPropValue:    // Return our current value
  336.                 outResult->n1.n2.vt = VT_BSTR;
  337.                 outResult->n1.n2.n3.bstrVal = SysAllocStringLen(mValue, strlen(mValue));
  338.                 break;
  339.  
  340.             default:
  341.                 return DISP_E_MEMBERNOTFOUND;
  342.         }
  343.     }
  344.     else if (inFlags & DISPATCH_PROPERTYPUT)    // else if this is a put property call
  345.     {
  346.         // Make sure that we have at least one parameter and that it is either a str or can be made into one
  347.         if (inParams->cArgs < 1)
  348.             return DISP_E_BADPARAMCOUNT;
  349.  
  350.         switch (inDispID)
  351.         {
  352.             case kPropName:    // This is a read-only property
  353.             {
  354.                 Result = DISP_E_MEMBERNOTFOUND;
  355.                 break;
  356.             }
  357.                     
  358.             case kPropValue:    // Change the current value to the one supplied
  359.             {
  360.                 Char8*             NewValue = VarGetBStr(inParams->rgvarg);
  361.                 AXDrawContext     Context;
  362.                 
  363.                 // Check for oversized value, then copy    
  364.                 if ( strlen(NewValue) > 255 )
  365.                 {
  366.                     strncpy(mValue, NewValue, 255);
  367.                     mValue[255] = 0;
  368.                 }
  369.                 else
  370.                     strcpy(mValue, NewValue);
  371.                 
  372.                 // Invalidate the context so the new value will be drawn
  373.                 if ( mContainerSiteP->AcquireContext(mActiveContext->GetContextID(), &Context) == S_OK )
  374.                 {
  375.                     InvalRect(&Context.Location);
  376.                     mContainerSiteP->ReleaseContext(&Context);
  377.                 }
  378.                 break;
  379.             }
  380.  
  381.             default:
  382.                 return DISP_E_MEMBERNOTFOUND;
  383.         }
  384.     }
  385.  
  386.     return Result;
  387. }
  388.  
  389.  
  390. #pragma mark === CJSButton::CBaseCPServer Override Methods ===
  391.  
  392. //=-----------------------------------------------------------------------------
  393. //  CJSButtonControl::BroadcastMessage
  394. //  Override of CBaseCPServer::BroadcastMessage
  395. //  Overriding this method allows controls to fire events
  396. //=-----------------------------------------------------------------------------
  397. //
  398. STDMETHODIMP
  399. CJSButtonControl::BroadcastMessage(REFIID inRefID, Int32 inMessageID, IUnknown* inTarget, void* inUserData)
  400. {
  401. #pragma unused (inUserData)
  402.     AXErrorCode    err = S_OK;
  403.  
  404.     // if this is the broadcast for the JSButton outgoing event dispatch interface
  405.     if ( inRefID == IID_IDispatch )
  406.     {
  407.         IDispatch*    target = (IDispatch*) inTarget;        // Should be an IDispatch interface
  408.         DISPID        DispID;                                // DispID from the client
  409.         char*        Name = (char*) CoTaskMemAlloc(16);    // Allocate memory to hold the name we'll ask for
  410.         
  411.         // Setup the correct name of the event
  412.         switch ( inMessageID )
  413.         {
  414.             case kEventOnClick:
  415.                 strcpy(Name, "onClick");
  416.                 break;
  417.  
  418.             default:
  419.                 err = E_FAIL;
  420.                 break;
  421.         }
  422.         
  423.         // if this is legally one of our events,
  424.         // Invoke the event handler
  425.         if ( err == S_OK )
  426.         {
  427.             // if we can find a DISPID for this name
  428.             // invoke the event handler
  429.             if ( (err = target->GetIDsOfNames(IID_NULL, &Name, 1, 0, &DispID)) == S_OK )
  430.             {
  431.                 DISPPARAMS         dispParams;
  432.                 VARIANT         dummyResult;
  433.                 EXCEPINFO         excepInfo;
  434.                 unsigned int    ArgError = 0;
  435.                 
  436.                 // Set up for the Invoke call
  437.                 dispParams.rgvarg = nil;
  438.                 dispParams.rgdispidNamedArgs = NULL;
  439.                 dispParams.cArgs = 0;
  440.                 dispParams.cNamedArgs = 0;
  441.                 memset(&excepInfo, 0, sizeof(EXCEPINFO));
  442.                 VariantInit(&dummyResult);
  443.                 
  444.                 // invoke the event handler
  445.                 err = target->Invoke(DispID, IID_NULL, 0, DISPATCH_METHOD, &dispParams, &dummyResult, &excepInfo, &ArgError);
  446.                 
  447.                 VariantClear(&dummyResult);
  448.             }
  449.         }
  450.             
  451.         // Free the name allocation
  452.         CoTaskMemFree(Name);
  453.     }
  454.             
  455.         
  456.     return err;
  457. }
  458.  
  459. #pragma mark === CJSButtonControl::private methods ===
  460.  
  461. //=--------------------------------------------------------------------------=
  462. //  CJSButtonControl::WaitClick    
  463. //=--------------------------------------------------------------------------=
  464.  
  465. void CJSButtonControl::WaitClick(void)
  466. {
  467.     if ( mScriptClick )
  468.     {
  469.         long FinalTicks;
  470.         
  471.         Delay(120, &FinalTicks);
  472.     }
  473.     else
  474.         while (StillDown()) ;
  475. }
  476.  
  477. //=--------------------------------------------------------------------------=
  478. //    CJSButtonControl::GetValueFromPropertyBag
  479. //=--------------------------------------------------------------------------=
  480. //
  481. void CJSButtonControl::GetValueFromPropertyBag(IPropertyBag* PropertyBag, IErrorLog* ErrorLog)
  482. {
  483.     VARIANT    v;
  484.  
  485.     // Initialize the variant
  486.     VariantInit(&v);
  487.     v.n1.n2.vt = VT_BSTR;
  488.     v.n1.n2.n3.bstrVal = nil;
  489.  
  490.     // Get the value
  491.     if ( PropertyBag->Read("value", &v, ErrorLog) == S_OK && v.n1.n2.n3.bstrVal)
  492.     {
  493.         char* TempStr = VarGetBStr(&v);
  494.         
  495.         // Assign the string to our member ID
  496.         if ( TempStr )
  497.         {
  498.             Int16    ValueLen = strlen(TempStr);
  499.  
  500.             if (ValueLen > 255)
  501.                 ValueLen = 255;
  502.             strncpy(mValue, TempStr, ValueLen);
  503.         }
  504.         
  505.         // Free the Variant string
  506.         SysFreeString(v.n1.n2.n3.bstrVal);
  507.         v.n1.n2.n3.bstrVal = nil;
  508.     }
  509.     else
  510.         strcpy(mValue, "ClickMe");
  511. }
  512.  
  513.  
  514.